<?php
define("CABINET_UNDERSCORE", "_");
define("CABINET_EXTENSION", ".php");

/**
 * Set of utilities to manage the requirement of files
 * 
 * <p>This class includes a series of methods to help include
 * files and packages.  The goal is to ensure that a file is
 * included only once without requiring the overhead of a
 * require_once call.
 * <p>Note that in order for the utilities to work they must
 * be in the Utils directory and this file must be at the
 * beside them.  Feel free to copy this file and paste it
 * in the top level of your project to take advantage of its
 * functionality.  Just be sure to rename it to avoid a
 * naming conflict.
 *
 * @package junction.utils
 * @author Alexander Schearer <aas11@duke.edu>
 */
class Junction_FileCabinet {
	/**
	 * Includes a specified class once and only once
	 * 
	 * <p>Be aware that the class must follow the PEAR naming convention.
	 * The extension should be omitted and is assumed to be the 
	 * CABINET_EXTENSION.
	 *
	 * @param String $classname
	 */
	public static function using($classname) {
		 if (!(class_exists($classname, false) || 
		 	   interface_exists($classname, false))) {
		 	require(dirname(__FILE__) . 
	 				DIRECTORY_SEPARATOR . 
	 				Junction_FileCabinet::classtofile($classname) . 
	 				CABINET_EXTENSION);
		 }
	}
	
	/**
	 * Include all the files in a given directory as a package
	 * 
	 * <p>Be aware that the package should be specified following PEAR
	 * notation.
	 * <p>This method works by marking directories it has already been to.
	 *
	 * @param String $directory
	 */
	public static function package($path) {
		static $packages = array();
		if (!isset($packages[$path])) {
			$packages[$path] = true;
			$fullpath = dirname(__FILE__) . DIRECTORY_SEPARATOR . Junction_FileCabinet::classtofile($path);
			$directory = new DirectoryIterator($fullpath);
			foreach ($directory as $file) {
				if (!is_dir($fullpath . DIRECTORY_SEPARATOR . $file)) {
					Junction_FileCabinet::using($path . CABINET_UNDERSCORE . basename($file, CABINET_EXTENSION));
				}
			}
		}
	}
	
	/**
	 * Include a given file once and only once
	 * 
	 * <p>This will include a file which does not follow the
	 * PEAR naming convention.  As a result the complete
	 * path must be specified.
	 *
	 * @param String $path
	 */
	public static function get($path) {
		static $includes = array();
		if (!isset($includes[$path])) {
			$includes[$path] = true;
			require($path);
		}
	}
	
	/**
	 * Convert a class name to its file name without the extension
	 *
	 * @param String $classname
	 * @return String
	 */
	public static function classtofile($classname) {
		return str_replace(CABINET_UNDERSCORE, DIRECTORY_SEPARATOR, $classname);
	}
	
	/**
	 * Convert a file name with extension to a class name
	 *
	 * @param String $file
	 * @return String
	 */
	public static function filetoclass($file) {
		return str_replace(DIRECTORY_SEPARATOR, CABINET_UNDERSCORE, basename($file, CABINET_EXTENSION));
	}
}
?>